package io.kiki.stack.netty.invoker;


import io.kiki.stack.netty.channelManager.Channel;
import io.kiki.stack.netty.channelManager.ChannelManagerImpl;
import io.kiki.stack.netty.channelManager.Url;
import io.kiki.stack.netty.command.Command;
import io.kiki.stack.netty.command.CommandFactory;
import io.kiki.stack.netty.exception.RemotingException;
import io.kiki.stack.netty.util.InetSocketAddressUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Setter
@Getter
public class ServerInvoker extends Invoker {

    public ServerInvoker(CommandFactory commandFactory) {
        super(commandFactory);
    }

    public ServerInvoker(CommandFactory commandFactory, ChannelManagerImpl channelManager) {
        super(commandFactory, channelManager);
    }

    @Override
    public Object invokeSync(Url url, Object request, RequestContext requestContext, int timeoutMillis) throws RemotingException, InterruptedException {
        Channel channel = this.channelManager.get(url.getId());
        if (null == channel) {
            throw new RemotingException("Client address [" + url.getId() + "] not connected yet!");
        }
        this.channelManager.check(channel);
        return this.invokeSync(channel, request, requestContext, timeoutMillis);
    }

    @Override
    public void oneway(Url url, Object request, RequestContext requestContext) throws RemotingException {
        Channel conn = this.channelManager.get(url.getId());
        if (null == conn) {
            throw new RemotingException("Client address [" + url.getOriginUrl() + "] not connected yet!");
        }
        this.channelManager.check(conn);
        this.oneway(conn, request, requestContext);
    }

    @Override
    public RpcResponseFuture invokeWithFuture(Url url, Object request, RequestContext requestContext, int timeoutMillis) throws RemotingException {
        Channel conn = this.channelManager.get(url.getId());
        if (null == conn) {
            throw new RemotingException("Client address [" + url.getId() + "] not connected yet!");
        }
        this.channelManager.check(conn);
        return this.invokeWithFuture(conn, request, requestContext, timeoutMillis);
    }

    @Override
    public void invokeWithCallback(Url url, Object request, RequestContext requestContext, Callback callback, int timeoutMillis) throws RemotingException {
        Channel channel = this.channelManager.get(url.getId());
        if (null == channel) {
            throw new RemotingException("Client address [" + url.getId() + "] not connected yet!");
        }
        this.channelManager.check(channel);
        this.invokeWithCallback(channel, request, requestContext, callback, timeoutMillis);
    }

    @Override
    protected void preProcessInvokeContext(RequestContext requestContext, Command command, Channel channel) {
        if (null != requestContext) {
            requestContext.putIfAbsent(RequestContext.SERVER_REMOTE_IP, InetSocketAddressUtil.parseRemoteIp(channel.getChannel()));
            requestContext.putIfAbsent(RequestContext.SERVER_REMOTE_PORT, InetSocketAddressUtil.parseRemotePort(channel.getChannel()));
            requestContext.putIfAbsent(RequestContext.SERVER_LOCAL_IP, InetSocketAddressUtil.parseLocalIp(channel.getChannel()));
            requestContext.putIfAbsent(RequestContext.SERVER_LOCAL_PORT, InetSocketAddressUtil.parseLocalPort(channel.getChannel()));
            requestContext.putIfAbsent(RequestContext._INVOKE_REQUEST_ID, command.getId());
        }
    }
}
